package co.dreamapps.dodoattack.activities;


import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.WakeLockOptions;
import org.andengine.engine.options.resolutionpolicy.FillResolutionPolicy;
import org.andengine.entity.IEntity;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.IOnSceneTouchListener;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.text.Text;
import org.andengine.entity.util.FPSLogger;
import org.andengine.input.touch.TouchEvent;
import org.andengine.input.touch.detector.ClickDetector;
import org.andengine.input.touch.detector.ClickDetector.IClickDetectorListener;
import org.andengine.input.touch.detector.ScrollDetector;
import org.andengine.input.touch.detector.ScrollDetector.IScrollDetectorListener;
import org.andengine.input.touch.detector.SurfaceScrollDetector;
import org.andengine.opengl.font.Font;
import org.andengine.opengl.font.FontFactory;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.TextureRegion;
import org.andengine.ui.activity.SimpleBaseGameActivity;

import co.dreamapps.dodoattack.configuration.Persistence;
import co.dreamapps.dodoattack.configuration.Constants;
import co.dreamapps.dodoattack.model.Background;
import co.dreamapps.dodoattack.network.MessageDistpacher;
import co.dreamapps.dodoattack.network.NetworkUtility;
import protocol.ConnectionDiscover;
import protocol.GameToConnect;
import protocol.OnConnectionUpdatesListener;
import protocol.RoomConnection;
import protocol.User;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnShowListener;
import android.graphics.Color;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.text.InputType;
import android.view.Gravity;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.Toast;

public class MenuScrollerActivity extends SimpleBaseGameActivity implements IScrollDetectorListener, IOnSceneTouchListener, IClickDetectorListener, OnConnectionUpdatesListener {

	/**
	 * Constantes
	 */
	protected static int CAMERA_WIDTH = 1080;
	protected static int CAMERA_HEIGHT = 720;
	protected static int FONT_SIZE = 10;	
	protected static int PADDING = CAMERA_WIDTH/6;
	protected static int MENUITEMS = 3;
	private static final String GAME_SPACE = "dododemo";

	/**
	 * Recursos
	 */
	private Font font;
	private BitmapTextureAtlas atlasFont; 
	private BitmapTextureAtlas atlasMenu;
	private BitmapTextureAtlas chickenBitmapTextureAtlas;
	private TextureRegion textureL;
	private TextureRegion textureR;
	private TextureRegion chickenRegion;

	/**
	 * Scene
	 */
	private Scene sceneMenu;
	private Camera cameraMenu;

	/**
	 * Sprites
	 */
	private Sprite spriteL;
	private Sprite spriteR;
	private Background background;
	private ArrayList<IEntity> chickens = new ArrayList<IEntity>();

	/**
	 *  Scrolling
	 */
	private SurfaceScrollDetector scrollDetectorMenu;
	private ClickDetector clickDetectorMenu;
	private float mMinX = 0;
	private float mMaxX = 0;
	private float mCurrentX = 0;
	private int iItemClicked = -1;
	private Rectangle rectangleScrollBar;

	/**
	 * Connection
	 */
	private ConnectionDiscover discover;
	private RoomConnection room;
	private String password;
	private ArrayList<User> users = new ArrayList<User>();
	private boolean announcingGame = false;
	private boolean gameStarted = false;
	private boolean connectionStarted = false;

	// ************************************* ANDENGINE *************************************

	@Override
	protected void onCreate(Bundle pSavedInstanceState) {
		// Game mode
		Bundle bundle = getIntent().getExtras();
		String message = bundle.getString(Constants.MODE);
		if(message == null)
			finish();
		else if(message.equals(Constants.MODE_RACING)) {
			password = bundle.getString(Constants.PASSWORD);
			announcingGame = true;
		} else if(message.equals(Constants.MODE_ATTACKING))
			announcingGame = false;
		else
			finish();

		Toast.makeText(getApplicationContext(), announcingGame ? " Password is: " + password: "Select an user in the list", Toast.LENGTH_SHORT).show();
		discover = new ConnectionDiscover(GAME_SPACE, NetworkUtility.getIpAddr((WifiManager) getSystemService(WIFI_SERVICE)), this, MessageDistpacher.INSTANCE);
		if(announcingGame) {
			Persistence config = new Persistence(getApplicationContext());
			room = discover.startAnnouncingGame(config.username, password);
		}
		super.onCreate(pSavedInstanceState);
	}

	@Override
	public EngineOptions onCreateEngineOptions() {
		this.cameraMenu = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new FillResolutionPolicy(), cameraMenu);
		engineOptions.setWakeLockOptions(WakeLockOptions.SCREEN_ON);
		return engineOptions;
	}

	@Override
	protected void onCreateResources() throws IOException {

		// Paths
		FontFactory.setAssetBasePath("fonts/");
		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("imagenes/");

		// Fondo
		background = new Background();
		background.menuScrollerMode();
		background.onCreateResourcesBackground(this.getTextureManager(), this);

		// Font
		atlasFont = new BitmapTextureAtlas(getTextureManager(), 1080, 720);
		font = FontFactory.createFromAsset(getFontManager(), atlasFont, getAssets(), "BaconFarm.ttf", 55, true, Color.DKGRAY);		
		mEngine.getTextureManager().loadTexture(this.atlasFont);
		mEngine.getFontManager().loadFonts(this.font);

		// Texture for chickens
		chickenBitmapTextureAtlas = new BitmapTextureAtlas(getTextureManager(), 1080, 720, TextureOptions.DEFAULT);
		chickenRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(chickenBitmapTextureAtlas, this, "happy_dodo.png", 0, 0);
		mEngine.getTextureManager().loadTexture(chickenBitmapTextureAtlas);

		// Textures for menu arrows
		atlasMenu = new BitmapTextureAtlas(getTextureManager(), 130, 65, TextureOptions.DEFAULT);
		textureL = BitmapTextureAtlasTextureRegionFactory.createFromAsset(atlasMenu, this, "fl.png", 0, 0);
		textureR = BitmapTextureAtlasTextureRegionFactory.createFromAsset(atlasMenu, this, "fr.png", 65, 0);
		mEngine.getTextureManager().loadTexture(atlasMenu);

	}

	@Override
	protected Scene onCreateScene() {

		// Configuring engine
		mEngine.registerUpdateHandler(new FPSLogger());
		sceneMenu = new Scene();
		scrollDetectorMenu = new SurfaceScrollDetector(this);
		clickDetectorMenu = new ClickDetector(this);
		sceneMenu.setOnSceneTouchListener(this);
		sceneMenu.setTouchAreaBindingOnActionDownEnabled(true);
		sceneMenu.setOnSceneTouchListenerBindingOnActionDownEnabled(true);

		// Fondo
		background.onCreateSceneBackground(getVertexBufferObjectManager());		
		sceneMenu.setBackground(background.getBackground());

		// Todo en cero para que no aparezca la barra
		rectangleScrollBar = new Rectangle(0, 0, 0, 0, getVertexBufferObjectManager());		
		rectangleScrollBar.setColor(1,0,0);		
		sceneMenu.attachChild(rectangleScrollBar);

		if(announcingGame) {
			Text titulo = new Text(CAMERA_WIDTH/2, CAMERA_HEIGHT/2, font, "Waiting for opponent to connect", getVertexBufferObjectManager());
			titulo.setText("Waiting for opponent to connect");
			sceneMenu.attachChild(titulo);
			Text passwordText = new Text(CAMERA_WIDTH/2, CAMERA_HEIGHT/3, font, "Password is: "+password, getVertexBufferObjectManager());
			titulo.setText("Waiting for opponent to connect");
			sceneMenu.attachChild(passwordText);
		} else {
			// Arrows
			// Se le toma el ancho de spriteL para poder posicionar al spriteR. son del mismo ancho.
			spriteL = new Sprite(0,CAMERA_HEIGHT/4,textureL, getVertexBufferObjectManager());
			spriteR = new Sprite(cameraMenu.getCenterX()+CAMERA_WIDTH/2-spriteL.getWidth(),CAMERA_HEIGHT/4,textureR, getVertexBufferObjectManager());
			sceneMenu.attachChild(spriteR);
			spriteL.setVisible(false);
			sceneMenu.attachChild(spriteL);
			// Updating users
			updateUsers();
		}

		return sceneMenu;
	}

	// ************************************* ANDENGINE *************************************

	// ************************************* LISTENERS *************************************

	@Override
	public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
		if(!announcingGame) {
			this.clickDetectorMenu.onTouchEvent(pSceneTouchEvent);
			this.scrollDetectorMenu.onTouchEvent(pSceneTouchEvent);
		}
		return true;
	}

	@Override
	public void onClick(ClickDetector pClickDetector, final int pPointerID, float pSceneX, float pSceneY) {
		if (iItemClicked != -1 && !announcingGame && !connectionStarted) {

			final GameToConnect gameToConnect = (GameToConnect) users.get(iItemClicked);
			final Context mContext = this;

			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					final AlertDialog.Builder alert = new AlertDialog.Builder(mContext);

					alert.setTitle("Connecting to "+gameToConnect.name);
					alert.setMessage("Write the password");

					final EditText editText = new EditText(mContext);
					editText.setTextSize(20f);
					editText.setText("");
					editText.setGravity(Gravity.CENTER_HORIZONTAL);
					editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);

					alert.setView(editText);

					alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int whichButton) {
							Persistence config = new Persistence(mContext);
							discover.connectToGame(gameToConnect, config.username, editText.getText().toString());
						}
					});

					alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int whichButton) {

						}
					});

					final AlertDialog dialog = alert.create();
					dialog.setOnShowListener(new OnShowListener() {
						@Override
						public void onShow(DialogInterface dialog) {
							editText.requestFocus();
							final InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
							imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
						}
					});
					dialog.show();
				}
			});
		}
	}

	@Override
	public void onScrollStarted(ScrollDetector pScollDetector, int pPointerID, float pDistanceX, float pDistanceY) {}

	@Override
	public void onScroll(ScrollDetector pScollDetector, int pPointerID, float pDistanceX, float pDistanceY) {

		if(!announcingGame) {
			//Disable the menu arrows left and right (15px padding)
			if(cameraMenu.getXMin() <= 15)
				spriteL.setVisible(false);
			else
				spriteL.setVisible(true);

			if(cameraMenu.getXMin() > mMaxX-15)
				spriteR.setVisible(false);
			else
				spriteR.setVisible(true);

			//Return if ends are reached
			if(((mCurrentX - pDistanceX) < mMinX)  ) {                	
				return;
			} else if((mCurrentX - pDistanceX) > mMaxX) {
				return;
			}
			//Center camera to the current point
			this.cameraMenu.offsetCenter(-pDistanceX,0);
			mCurrentX -= pDistanceX;

			//Set the scrollbar with the camera
			float tempX = cameraMenu.getCenterX()-CAMERA_WIDTH/2;

			// add the % part to the position
			tempX+= (tempX/(mMaxX+CAMERA_WIDTH))*CAMERA_WIDTH;

			//set the position
			rectangleScrollBar.setPosition(tempX, rectangleScrollBar.getY());

			//set the arrows for left and right
			spriteR.setPosition(cameraMenu.getCenterX()+CAMERA_WIDTH/2-spriteR.getWidth(),spriteR.getY());
			spriteL.setPosition(cameraMenu.getCenterX()-CAMERA_WIDTH/2+spriteL.getWidth(),spriteL.getY());

			//Because Camera can have negativ X values, so set to 0
			if(this.cameraMenu.getXMin() < 0) {
				this.cameraMenu.offsetCenter(0,0);
				mCurrentX=0;
			}
		}
	}

	@Override
	public void onScrollFinished(ScrollDetector pScollDetector, int pPointerID, float pDistanceX, float pDistanceY) {}

	// ************************************* LISTENERS *************************************

	// ********************************** LAYERS HANDLING **********************************

	public void updateUsers() {

		// Removing last users
		for (int i = 0; i < chickens.size(); i++) {
			remove(sceneMenu, chickens.get(i));
			sceneMenu.unregisterTouchArea(chickens.get(i));
		}
		chickens.clear();

		if(users.size() > 0) {
			// Add new users
			int posX = CAMERA_WIDTH/2;
			int posY = CAMERA_HEIGHT/4;
			int iItem = 0;
			for (User user : users) {
				final int itemToLoad = iItem;
				Sprite sprite = new Sprite(posX,posY, chickenRegion, getVertexBufferObjectManager()){
					public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
						iItemClicked = itemToLoad;
						return false;
					}
				};
				iItem++;
				Text titulo = new Text(sprite.getWidth()/2, sprite.getHeight()*1.25f, font, user.name, getVertexBufferObjectManager());
				titulo.setText(user.name);
				sprite.attachChild(titulo);
				chickens.add(sprite);
				sceneMenu.attachChild(sprite);
				sceneMenu.registerTouchArea(sprite);
				posX += PADDING+sprite.getWidth();
			}
			mMaxX = posX - CAMERA_WIDTH;
		} else {
			Text message = new Text(CAMERA_WIDTH/2, CAMERA_HEIGHT/2, font, "No user available", getVertexBufferObjectManager());
			message.setText("No user available");
			chickens.add(message);
			sceneMenu.attachChild(message);
		}
	}

	public void remove(final IEntity from, final IEntity entityToRemove) {
		runOnUpdateThread(new Runnable() {
			@Override
			public void run() {
				from.detachChild(entityToRemove);
			}
		});
	}

	// ********************************** LAYERS HANDLING **********************************

	// ********************************** PROTOCOL EVENTS **********************************

	@Override
	public void onGamesListUpdated(Collection<GameToConnect> users) {
		if(!announcingGame && !gameStarted) {
			this.users.clear();
			this.users.addAll(users);
			updateUsers();
		}
	}

	@Override
	public void onGameStart(long timeDifference, int countDown) {
		if(!gameStarted) {
			gameStarted = true;
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					Intent intent = new Intent(MenuScrollerActivity.this, GameActivity.class);
					if(announcingGame) {
						intent.putExtra(Constants.MODE, Constants.MODE_RACING);
					} else {
						intent.putExtra(Constants.MODE, Constants.MODE_ATTACKING);
					}
					intent.putExtra(Constants.ROUND, 0);
					startActivity(intent);
				}
			});
		}
	}

	@Override
	public void onUsersListUpdated(Collection<User> users) {
		if(!gameStarted) {
			// Starting the game with only one player
			room.startGame();
		}
	}

	@Override
	public void onConnectionConfirmed(final boolean confirmed) {
		if(!gameStarted && !connectionStarted) {
			connectionStarted = confirmed;
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					Toast.makeText(getApplicationContext(), (confirmed ? "Confirmed" : "Incorrect password"), Toast.LENGTH_SHORT).show();
				}
			});
		}
	}

	// ********************************** PROTOCOL EVENTS **********************************

	// *********************************** CICLO DE VIDA ***********************************

	@Override
	protected void onPause() {
		if(!gameStarted && room != null) {
			room.stopGameAnnouncing();
		}
		finish();
		super.onPause();
	}

	// *********************************** CICLO DE VIDA ***********************************
}
